#include "../include/head.h"
#include "../include/func.h"

Tag command_transfer(const char *cmd_name) {
    if (cmd_name == NULL) return(Tag) TAGUNKNOWN;
    if (strcmp(cmd_name, "cd") == 0) return TAGCD;
    if (strcmp(cmd_name, "ls") == 0) return TAGLS;
    if (strcmp(cmd_name, "rm") == 0) return TAGREMOVE;
    if (strcmp(cmd_name, "pwd") == 0) return TAGPWD;
    if (strcmp(cmd_name, "mkdir") == 0) return TAGMKDIR;
    if (strcmp(cmd_name, "gets") == 0) return TAGGETS;
    if (strcmp(cmd_name, "puts") == 0) return TAGPUTS;
    return(Tag) TAGUNKNOWN;
}

// 根据操作码获取命令字符串
const char *get_cmd_name(Tag cmd_tag) {
    switch (cmd_tag) {
        case TAGCD: return "cd";
        case TAGLS: return "ls";
        case TAGREMOVE: return "rm";
        case TAGPWD: return "pwd";
        case TAGMKDIR: return "mkdir";
        case TAGGETS: return "gets";
        case TAGPUTS: return "puts";
        default: return "unknown";
    }
}

Tag get_cmd_tag(const char *cmd_name) {
    return command_transfer(cmd_name);
}

int init_cmd(char *line, pcmd_t pcmd)
{
    // 参数检查
    ERROR_CHECK(line, NULL, "init_cmd error");
    ERROR_CHECK(pcmd, NULL, "init_cmd error");

    //初始化
    pcmd->argc = 0;
    pcmd->cmd_tag =(Tag)TAGUNKNOWN;


    //使用strtok将line拆分
    char *token;
    const char s[] = {' ', '\n'};
    
    //首次使用strtok时，需传入待分割的字符串和分隔符集合
    //之后再调用，第一个参数设为NULL，表示从继续上次的位置分割
    token = strtok(line, s);
    while (NULL != token && pcmd->argc < MAX_WORDNUM) {
        strcpy(pcmd->cmd[pcmd->argc], token);
        pcmd->argc++;
        token = strtok(NULL, s);
    }
    
    if (pcmd->argc > 0) {
        pcmd->cmd_tag = get_cmd_tag(pcmd->cmd[0]);
        if (pcmd->cmd_tag ==(Tag) TAGUNKNOWN) {
            fprintf(stderr, "Unknown command: %s\n", pcmd->cmd[0]);
            return -1;
        }
    }
    
    return 0;

}

//打印命令
int print_cmd(pcmd_t pcmd)
{
    // 参数检查
    ERROR_CHECK(pcmd, NULL, "print_cmd error");

     printf("cmd_tag: %d, cmd_name: %s, args: ",
           pcmd->cmd_tag, get_cmd_name(pcmd->cmd_tag));
    for (int i = 0; i < pcmd->argc; ++i) {
        printf("%s ", pcmd->cmd[i]);
    }
    printf("\n");
    
    return 0;

}

//检查命令是否合法

int cmd_check(pcmd_t pcmd)
{
    if (pcmd == NULL || pcmd->argc == 0) {
        return -1;
    }
    

    // 直接检查cmd_tag是否有效
    if (pcmd->cmd_tag >= TAGCD && pcmd->cmd_tag <= TAGPUTS) {
        return 0;
    } else {
        return -1;
    }

}

//上传文件 - 不使用额外枚举
int upload(int fd_socket, char *filename) {
    if (filename == NULL || strlen(filename) == 0) {
        printf("Error: No filename specified!\n");
        return -1;
    }

    // 检查文件是否存在且是普通文件
    struct stat file_stat;
    if (stat(filename, &file_stat) == -1) {
        printf("Error: File '%s' not found!\n", filename);
        int flag = 0; // 0表示不允许传输
        send(fd_socket, &flag, sizeof(int), 0);
        return -1;
    }
    
    if (!S_ISREG(file_stat.st_mode)) {
        printf("Error: '%s' is not a regular file!\n", filename);
        int flag = 0; // 0表示不允许传输
        send(fd_socket, &flag, sizeof(int), 0);
        return -1;
    }
    
    // 发送传输允许标志
    int flag = 1; // 1表示允许传输
    send(fd_socket, &flag, sizeof(int), 0);
    
    // 打开文件
    int fd_file = open(filename, O_RDONLY);
    EXIT_CHECK(fd_file, -1, "open file");
    
    train_t train;
    ssize_t read_bytes;
    int total_sent = 0;
    
    printf("Uploading file: %s (Size: %ld bytes)\n", filename, file_stat.st_size);
    
    // 发送文件大小 - 使用特殊tag值来标识文件开始
    train.tag = 100; // 用100表示文件开始
    train.data_length = sizeof(file_stat.st_size);
    memcpy(train.data, &file_stat.st_size, train.data_length);
    
    // 发送文件大小
    send(fd_socket, &train.tag, sizeof(train.tag), 0);
    send(fd_socket, &train.data_length, sizeof(train.data_length), 0);
    send(fd_socket, train.data, train.data_length, 0);
    
    // 发送文件内容
    while ((read_bytes = read(fd_file, train.data, BUF_SIZE)) > 0) {
        train.tag = 101; // 用101表示文件数据
        train.data_length = read_bytes;
    
        // 发送文件数据
        send(fd_socket, &train.tag, sizeof(train.tag), 0);
        send(fd_socket, &train.data_length, sizeof(train.data_length), 0);
        send(fd_socket, train.data, train.data_length, 0);
    
        total_sent += read_bytes;
        printf("\rProgress: %.2f%% (%d/%ld bytes)",
               (double)total_sent / file_stat.st_size * 100, total_sent, file_stat.st_size);
        fflush(stdout);
    }
    
    // 发送传输完成标志
    train.tag = 102; // 用102表示文件结束
    train.data_length = 0;
    send(fd_socket, &train.tag, sizeof(train.tag), 0);
    send(fd_socket, &train.data_length, sizeof(train.data_length), 0);
    
    close(fd_file);
    printf("\nFile upload completed: %d bytes sent\n", total_sent);
    return 0;

}

//下载文件 - 不使用额外枚举
int download(int fd_socket, char *filename) {
    if (filename == NULL || strlen(filename) == 0) {
        printf("Error: No filename specified!\n");
        return -1;
    }

    // 接收传输标志
    int flag;
    recv(fd_socket, &flag, sizeof(int), MSG_WAITALL);
    
    if (flag == 0) {
        printf("Error: File not found on server or not a regular file\n");
        return -1;
    }
    
    // 创建文件
    int fd_file = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    EXIT_CHECK(fd_file, -1, "create file");
    
    train_t train;
    long file_size = 0;
    int total_received = 0;
    
    // 接收文件大小
    recv(fd_socket, &train.tag, sizeof(train.tag), MSG_WAITALL);
    recv(fd_socket, &train.data_length, sizeof(train.data_length), MSG_WAITALL);
    
    if (train.tag == 100 && train.data_length == sizeof(long)) { // 100表示文件开始
        recv(fd_socket, train.data, train.data_length, MSG_WAITALL);
        memcpy(&file_size, train.data, train.data_length);
        printf("Downloading file: %s (Size: %ld bytes)\n", filename, file_size);
    }
    // 接收文件内容
    while (1) {
        // 接收标签
        recv(fd_socket, &train.tag, sizeof(train.tag), MSG_WAITALL);
    
        // 接收数据长度
        recv(fd_socket, &train.data_length, sizeof(train.data_length), MSG_WAITALL);
    
        // 检查传输结束
        if (train.tag == 102 && train.data_length == 0) { // 102表示文件结束
            printf("\nFile download completed: %d bytes received\n", total_received);
            break;
        }
    
        // 接收文件数据
        if (train.tag == 101 && train.data_length > 0) { // 101表示文件数据
            recv(fd_socket, train.data, train.data_length, MSG_WAITALL);
            write(fd_file, train.data, train.data_length);
    
            total_received += train.data_length;
            if (file_size > 0) {
                printf("\rProgress: %.2f%% (%d/%ld bytes)",
                       (double)total_received / file_size * 100, total_received, file_size);
                fflush(stdout);
            }
        }
    }
    close(fd_file);
    
    if (total_received == 0) {
        printf("Error: No data received\n");
        unlink(filename);
        return -1;
    }
    return 0;

}

